﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using PaperPluginUtilities;

namespace HTMLTablePageScanner
{
    /// <summary>
    /// Helper class to scan over html and see if we can't sort out what is good
    /// text and bad text.
    /// </summary>
    public static class HTMLTextScanner
    {
        static private string[] textNodes = new string[] { "p", "#text" };

        static private string[] nodesToIgnoreResetOn = new string[] { "sub", "sup", "b", "i" };

        /// <summary>
        /// Scans over incoming links and returns links...
        /// </summary>
        /// <param name="source"></param>
        /// <param name="setText"></param>
        /// <returns></returns>
        public static IEnumerable<HtmlNode> ScanForText(this HtmlNode source,
            Action<string> setText, string[] linksYouCarAbout)
        {
            var allNodes = source.ScanSubNodes(n => nodesToIgnoreResetOn.Contains(n.Name) || textNodes.Contains(n.Name) || linksYouCarAbout.Contains(n.Name));

            ///
            /// Now, if any of these nodes has children, it could be there are nested interesting links. Surface them!
            /// 

            var interestingNodes = allNodes.SelectMany(n => ScanSubNodes(n, linksYouCarAbout));

            ///
            /// Try to track the text as it comes in now
            /// 

            string lastDescriptionSeen = "";
            bool ignoreNextReset = false;

            var descripScan = interestingNodes.Apply(n =>
            {
                string innerText = n.InnerText;
                bool dontResetThisTime = false;

                if (ignoreNextReset)
                {
                    lastDescriptionSeen += innerText;
                    setText(lastDescriptionSeen);
                    ignoreNextReset = false;
                    dontResetThisTime = true;
                }

                if (nodesToIgnoreResetOn.Contains(n.Name))
                {
                    lastDescriptionSeen += innerText;
                    setText(lastDescriptionSeen);
                    ignoreNextReset = true;
                    dontResetThisTime = true;
                }

                if (!dontResetThisTime && innerText.CleanHTMLText().IsNotTooSimpleDescription())
                {
                    lastDescriptionSeen = innerText.CleanHTMLText();
                    setText(lastDescriptionSeen);
                }
            });

            ///
            /// Pass on the ones that are interesting...
            /// 

            foreach (var item in descripScan.Where(n => linksYouCarAbout.Contains(n.Name)))
            {
                yield return item;
            }
        }

        /// <summary>
        /// If the node has children, see if we can look for one of the links we care about!
        /// </summary>
        /// <param name="n"></param>
        /// <param name="linksYouCarAbout"></param>
        /// <returns></returns>
        private static IEnumerable<HtmlNode> ScanSubNodes(HtmlNode n, string[] linksYouCarAbout)
        {
            IEnumerable<HtmlNode> seq = Enumerable.Empty<HtmlNode>();
            IEnumerable<HtmlNode> sourceAsSeq = new HtmlNode[] {n}.AsEnumerable();
            if (n.HasChildNodes && !linksYouCarAbout.Contains(n.Name))
            {
                seq = n.ScanSubNodes(node => linksYouCarAbout.Contains(node.Name));
            }

            return sourceAsSeq.Concat(seq);
        }
    }
}
